﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using Prueba.Model;
using DataMapper;
using System.ComponentModel;
using System.Windows.Data;
using Prueba.ViewModel.Utils;

namespace Prueba.ViewModel
{
    public class FdvGridViewModel:ViewModelBase
    {
        public System.Windows.Threading.Dispatcher dp;
        PropertyChangedEventHandler _CalcularTotalRecursoDelegate;
        private FdvDataMapper _FdvDataMapper;
        private IPublish _Publish;

        public string Territorio
        {
            get { return _Territorio; }
            set
            {
                if (_Territorio != value)
                {
                    _Territorio = value;
                    OnPropertyChanged(TerritorioPropertyName);
                }
            }
        }
        private string _Territorio;
        public const string TerritorioPropertyName = "Territorio";

        public IWaitMessage WaitMessage
        {
            get { return _WaitMessage; }
            set
            {
                if (_WaitMessage != value)
                {
                    _WaitMessage = value;
                    OnPropertyChanged(WaitMessagePropertyName);
                }
            }
        }
        private IWaitMessage _WaitMessage;
        public const string WaitMessagePropertyName = "WaitMessage";

        public RelayCommand SaveCommand
        {
            get 
            {
                if (this._SaveCommand == null)
                {
                    this._SaveCommand = new RelayCommand(p => this.AttempSave(), p => this.CanAttemptSave());
                }
                return this._SaveCommand; 
            }
        }
        private RelayCommand _SaveCommand;
        public const string SaveCommandPropertyName = "SaveCommand";

        public RelayCommand PublishCommand
        {
            get
            {
                if (this._PublishCommand == null)
                {
                    this._PublishCommand = new RelayCommand(p => this.AttempPublish(), p => this.CanAttemptPublish());
                }
                return this._PublishCommand; 
            }
        }
        private RelayCommand _PublishCommand;
        public const string PublishCommandPropertyName = "PublishCommand";


        public RelayCommand BorrarFiltrosCommand
        {
            get
            {
                if (this._BorrarFiltrosCommand == null)
                {
                    this._BorrarFiltrosCommand = new RelayCommand(p => this.AttempBorrarFiltros(), p => this.CanAttemptBorrarFiltros());
                }
                return this._BorrarFiltrosCommand;
            }
        }
        private RelayCommand _BorrarFiltrosCommand;

        public FdvVersion FdvVersion
        {
            get { return _FdvVersion; }
            set
            {
                if (_FdvVersion != value)
                {
                    _FdvVersion = value;
                    OnPropertyChanged(FdvVersionPropertyName);
                }
            }
        }
        private FdvVersion _FdvVersion;
        public const string FdvVersionPropertyName = "FdvVersion";

        public IUserConfirmation UserConfirmation
        {
            get { return _UserConfirmation; }
            set
            {
                if (_UserConfirmation != value)
                {
                    _UserConfirmation = value;
                    OnPropertyChanged(UserConfirmationPropertyName);
                }
            }
        }
        private IUserConfirmation _UserConfirmation;
        public const string UserConfirmationPropertyName = "UserConfirmation";

        public bool IsModified
        {
            get { return _IsModified; }
            set
            {
                if (_IsModified != value)
                {
                    _IsModified = value;
                    OnPropertyChanged(IsModifiedPropertyName);
                }
            }
        }
        private bool _IsModified;
        public const string IsModifiedPropertyName = "IsModified";

        /// <summary>
        /// Bandera que indica que se ha finalizado de guardar la información
        /// </summary>
        public bool IsDoneSaving
        {
            get { return _IsDoneSaving; }
            set
            {
                if (_IsDoneSaving != value)
                {
                    _IsDoneSaving = value;
                    OnPropertyChanged(IsDoneSavingPropertyName);
                }
            }
        }
        private bool _IsDoneSaving;
        public const string IsDoneSavingPropertyName = "IsDoneSaving";

        /// <summary>
        /// Propiedad que indica el row seleccionado. Sirve para la busqueda de pos
        /// </summary>
        public RowFdv SelectedRowFdv
        {
            get { return _SelectedRowFdv; }
            set
            {
                if (_SelectedRowFdv != value)
                {
                    _SelectedRowFdv = value;
                    OnPropertyChanged(SelectedRowFdvPropertyName);
                }
            }
        }
        private RowFdv _SelectedRowFdv;
        public const string SelectedRowFdvPropertyName = "SelectedRowFdv";

        /// <summary>
        /// Información de las columnas para los atributos del POS
        /// </summary>
        public ObservableCollection<PosColInfo> PosCols
        {
            get { return _PosCols; }
            set
            {
                if (_PosCols != value)
                {
                    _PosCols = value;
                    OnPropertyChanged(PosColsPropertyName);
                }
            }
        }
        private ObservableCollection<PosColInfo> _PosCols;
        public const string PosColsPropertyName = "PosCols";

        //public PosColVisibility PosColVisibility
        //{
        //    get { return _PosColVisibility; }
        //    set
        //    {
        //        if (_PosColVisibility != value)
        //        {
        //            _PosColVisibility = value;
        //            OnPropertyChanged(PosColVisibilityPropertyName);
        //        }
        //    }
        //}
        //private PosColVisibility _PosColVisibility;
        //public const string PosColVisibilityPropertyName = "PosColVisibility";
        
        /// <summary>
        /// Vista para el fitrado
        /// </summary>
        public CollectionViewSource CvsRows
        {
            get { return _CvsRows; }
            set
            {
                if (_CvsRows != value)
                {
                    _CvsRows = value;
                    OnPropertyChanged(CvsRowsPropertyName);
                }
            }
        }
        private CollectionViewSource _CvsRows;
        public const string CvsRowsPropertyName = "CvsRows";

        public ICollectionView CvRows
        {
            get { return _CvsRows.View; }
        }

        /// <summary>
        /// Contiene la configuracion de dimensiones para los encabezados de los grids
        /// </summary>
        public HeaderModel HeaderModel
        {
            get { return _HeaderModel; }
            set
            {
                if (_HeaderModel != value)
                {
                    _HeaderModel = value;
                    OnPropertyChanged(HeaderModelPropertyName);
                }
            }
        }
        private HeaderModel _HeaderModel;
        public const string HeaderModelPropertyName = "HeaderModel";

        /// <summary>
        /// Colección para el total por recurso (total vertical)
        /// </summary>
        public ObservableCollection<RowTotalRecurso> TotalesRecurso
        {
            get { return _TotalesRecurso; }
            set
            {
                if (_TotalesRecurso != value)
                {
                    _TotalesRecurso = value;
                    OnPropertyChanged(TotalesRecursoPropertyName);
                }
            }
        }
        private ObservableCollection<RowTotalRecurso> _TotalesRecurso;
        public const string TotalesRecursoPropertyName = "TotalesRecurso";

        /// <summary>
        /// Listado de recursos disponivles
        /// </summary>
        public ObservableCollection<Recurso> Recursos
        {
            get { return _Recursos; }
            set
            {
                if (_Recursos != value)
                {
                    _Recursos = value;
                    OnPropertyChanged(RecursosPropertyName);
                }
            }
        }
        private ObservableCollection<Recurso> _Recursos;
        public const string RecursosPropertyName = "Recursos";

        /// <summary>
        /// Colección con los datos de las cantidades capturadas para esta versión (ventana)
        /// </summary>
        public ObservableCollection<RowFdv> Rows
        {
            get { return _Rows; }
            set
            {
                if (_Rows != value)
                {
                    _Rows = value;
                    OnPropertyChanged(RowsPropertyName);
                }
            }
        }
        private ObservableCollection<RowFdv> _Rows;
        public const string RowsPropertyName = "Rows";

        public void LoadData()
        {
            this._FdvDataMapper.GetPivotFdv(ref this._FdvVersion, ref this._Recursos, ref this._Rows,ref this._TotalesRecurso,ref this._CalcularTotalRecursoDelegate,this.Territorio);
        }

        /// <summary>
        /// Calcula el total por recurso (total vertical) y el total de totales. 
        /// Se adjunta al manejador de evento para cuando la propiedad de cantidad cambie
        /// </summary>
        /// <param name="sender">Objeto ColFdv</param>
        /// <param name="args">Argumentos del evento PropertyChanged</param>
        public void CalcularTotalRecurso(object sender, PropertyChangedEventArgs args)
        {
            if (args.PropertyName.ToLower() == "cantidad")
            {
                ColFdv cf = sender as ColFdv;

                int tiempoImplementacion = 0;
                int visitasSugeridas = 0;
                int recursos = 0;
                int totalTiempoImplementacion = 0;
                int totalVisitasSugeridas = 0;

                if (args.PropertyName.ToLower() == "cantidad")
                {
                    foreach (RowFdv r in this._Rows)
                    {
                        if (r.Cols[cf.Recurso.RecursoId].Cantidad > 0)
                        {
                            tiempoImplementacion += (r.Cols[cf.Recurso.RecursoId].Cantidad * cf.Recurso.TiempoImplementacion);
                            visitasSugeridas += (cf.Recurso.VisitasSugeridas);
                            recursos += r.Cols[cf.Recurso.RecursoId].Cantidad;
                        }

                        totalTiempoImplementacion += r.Pos.TiempoImplementacion;
                        totalVisitasSugeridas += r.Pos.VisitasSugeridas;
                    }
                }

                //Asignar a total por Recursos
                cf.Recurso.IndTiempoImplementacion = tiempoImplementacion;
                cf.Recurso.IndVisitasSugeridas = visitasSugeridas;
                cf.Recurso.IndTotalRecursos = recursos;

                //Validar regla de máximo asignado
                if (recursos > cf.Recurso.MaxAsignado)
                {
                    cf.Recurso.IsMaximoAsignadoEx = true;
                    cf.OnPropertyChanged("IsCellAlarmed");
                }
                else
                {
                    cf.Recurso.IsMaximoAsignadoEx = false;
                    cf.OnPropertyChanged("IsCellAlarmed");
                }

                //Asignar el total de totales a la primera fila Tiempo Implementacion
                foreach (RowTotalRecurso rtr in this._TotalesRecurso)
                {
                    if (rtr.IndicadorName.ToLower() == "tiempo implementacion")
                        rtr.TotalTiempoImplementacion = totalTiempoImplementacion;

                    if (rtr.IndicadorName.ToLower() == "visitas sugeridas")
                        rtr.TotalVisitasSugeridas = totalVisitasSugeridas;
                } 

                //Si la cantidad ha sido modificada, poner bandera
                this.IsModified = true;
            }//endif
        }

        /// <summary>
        /// Evento para el filtrado de la vista
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void ApplyFilter(object sender, FilterEventArgs e)
        {
            RowFdv rf = e.Item as RowFdv;
            e.Accepted = true;

            foreach (Recurso r in this._Recursos)
            {
                if (r.FilterCantidad != null)
                {
                    if (rf.Cols[r.RecursoId].Cantidad != r.FilterCantidad)
                    {
                        e.Accepted = false;
                    }
                }
            }
        }

        #region Commands
        //Save
        public bool CanAttemptSave()
        {
            bool res = true;

            if (this.FdvVersion.IsClosed || !this.IsModified)
                res = false;

            return res;
        }

        public void AttempSave()
        {
            //guardar
            if (this.FdvVersion.IsPublished)
            {
                this.UserConfirmation.GetUserConfirmation("Si guarda la versión se publicarán los recursos que hayan sido modificados ¿Esta seguro de guardar?", "Guardar versión publicada");

                if (this.UserConfirmation.UserConfirmation)
                {
                    this.SaveAndPub();
                }
            }
            else
            {
                this.Save();
            }
        }

        //Publish
        public bool CanAttemptPublish()
        {
            bool canAttempt = true;

            if (this.FdvVersion.IsPublished || this.FdvVersion.IsClosed)
            {
                canAttempt = false;
            }

            return canAttempt;
        }

        public void AttempPublish()
        {
            this.UserConfirmation.GetUserConfirmation("¿Está seguro de publicar la versión?", "Publicar Versión");
            if (this.UserConfirmation.UserConfirmation)
            {
                if (this.IsModified)
                {
                    this.Save();
                }

                this.Publish();
            }
        }

        //Borrar Filtros
        public bool CanAttemptBorrarFiltros()
        {
            bool canAttempt = false;

            foreach (Recurso r in this.Recursos)
            {
                if (r.FilterCantidad != null)
                {
                    canAttempt = true;
                    break;
                }
            }

            return canAttempt;
        }

        public void AttempBorrarFiltros()
        {
            foreach (Recurso r in this.Recursos)
            {
                if (r.FilterCantidad != null)
                {
                    r.FilterCantidad = null;
                }
            }
            this.CvsRows.View.Refresh();
        }
        #endregion
        

        public void Save()
        {
            this.IsDoneSaving = false;
            new Threadable(delegate()
                {
                    this._FdvDataMapper.SaveFdvData(ref this._Rows, this.FdvVersion);
                    this.IsDoneSaving = true;
                    this.IsModified = false;
                    this.WaitMessage.Hide();

                    return 0;
                }
            );
            this.WaitMessage.Show();
        }

        public void SaveAndPub()
        {
            this.IsDoneSaving = false;
            

            new Threadable(delegate()
            {
                this._FdvDataMapper.SaveFdvData(ref this._Rows, this.FdvVersion);
                this.IsDoneSaving = true;
                this.IsModified = false;
                this.WaitMessage.Hide();

                Action a = () =>
                    {
                        this._Publish.Publish();
                    };

                if (dp != null)
                {
                    dp.BeginInvoke(a);
                    
                }
                

                return 0;
            }
            );
            this.WaitMessage.Show();
        }

        public void Publish()
        {
            this._Publish.Publish();
        }

        //Constructor----
        /// <summary>
        /// Constructor de la clase
        /// </summary>
        /// <param name="fdvDataMapper">DataMapper que contiene las funciones para recuperar los datos</param>
        public FdvGridViewModel(FdvDataMapper fdvDataMapper, long UnidVersion,IUserConfirmation UserConfirmation,IWaitMessage WaitMessage,string Territorio,IPublish Publish)
        {
            this._UserConfirmation = UserConfirmation;
            this._FdvVersion = new FdvVersion(UnidVersion, false,false);
            this._FdvDataMapper = fdvDataMapper;
            this._WaitMessage = WaitMessage;
            this._Territorio = Territorio;
            this._Publish = Publish;

            //Col info
            this.PosCols = new ObservableCollection<PosColInfo>();

            this.PosCols.Add(new PosColInfo("POS",true,this.PosCols));
            this.PosCols.Add(new PosColInfo("Nombre POS",true,this.PosCols));
            this.PosCols.Add(new PosColInfo("Razon Social", false, this.PosCols ));
            this.PosCols.Add(new PosColInfo("Canal", false, this.PosCols ));
            this.PosCols.Add(new PosColInfo("Sub Canal", false, this.PosCols ));
            this.PosCols.Add(new PosColInfo("Potencial", false, this.PosCols ));
            this.PosCols.Add(new PosColInfo("Estado", false, this.PosCols ));
            this.PosCols.Add(new PosColInfo("Municipio", false, this.PosCols ));
            this.PosCols.Add(new PosColInfo("Localidad", false, this.PosCols ));
            this.PosCols.Add(new PosColInfo("Colonia",false, this.PosCols ));
            this.PosCols.Add(new PosColInfo("Código Postal", false, this.PosCols ));

            //Cargar informacion de los encabezados
            this._HeaderModel = new HeaderModel()
            {
                HeaderHeight = 25,
                HeaderWidth = 105,
                TotalHeaderHeight = 25,
                TotalHeaderWidth = 80,
                PosHeaderWidth = 195
            };

            this._CalcularTotalRecursoDelegate = new PropertyChangedEventHandler(CalcularTotalRecurso);
            this.LoadData();

            this._CvsRows = new CollectionViewSource();
            this._CvsRows.Source = this.Rows;
            this._CvsRows.Filter += ApplyFilter;
            this.IsModified = false;
        }
    }
}
